package com.pragmatic.cryptography;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * SM4工具类(对称加密算法)
 *
 * @author wangdong
 * @since 2025/6/23 17:14
 */
public class SM4Util {

  // 算法名称SM4
  private static final String ALGORITHM_NAME = "SM4";
  // SM4/模式/填充方式
  private static final String DEFAULT_CIPHER_ALGORITHM = "SM4/CBC/PKCS5Padding";
  // SM4密钥长度128位
  private static final int KEY_SIZE = 128;

  /**
   * SM4 加密操作
   *
   * @param content 待加密明文内容
   * @param key 秘钥
   * @return 密文字符串格式
   */
  public static String encrypt(String content, String key, String iv) {
    try {
      Cipher cipher =
          Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
      // 向量参数
      IvParameterSpec ivParameterSpec = new IvParameterSpec(decodeToByte(iv));
      // 秘钥对象
      SecretKeySpec secretKeySpec = new SecretKeySpec(decodeToByte(key), ALGORITHM_NAME);
      cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
      byte[] result = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
      // 返回密文字符串格式
      return encodeToString(result);
    } catch (Exception e) {
      throw new RuntimeException("SM4加密失败", e);
    }
  }

  /**
   * Sm4 解密操作
   *
   * @param content 待解密密文内容
   * @param key 秘钥
   * @return 返回解密后的明文数据
   */
  public static String decrypt(String content, String key, String iv) {
    try {
      Cipher cipher =
          Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
      // 向量参数
      IvParameterSpec ivParameterSpec = new IvParameterSpec(decodeToByte(iv));
      // 秘钥对象
      SecretKeySpec secretKeySpec = new SecretKeySpec(decodeToByte(key), ALGORITHM_NAME);
      cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
      byte[] result = cipher.doFinal(decodeToByte(content));
      // 返回密文字符串格式
      return new String(result, StandardCharsets.UTF_8);
    } catch (Exception e) {
      throw new RuntimeException("SM4解密失败", e);
    }
  }

  /**
   * 生成SM4加密秘钥(用于内容加密)
   *
   * @return 秘钥字符串
   */
  public static String generateKey() {
    try {
      // 返回生成指定算法密钥生成器的 KeyGenerator对象
      KeyGenerator kg =
          KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
      // 设置秘钥长度
      kg.init(KEY_SIZE, new SecureRandom());
      // 生成一个密钥
      SecretKey secretKey = kg.generateKey();
      byte[] secretKeyByte = secretKey.getEncoded();
      // 返回字符串格式秘钥
      return encodeToString(secretKeyByte);
    } catch (Exception e) {
      throw new RuntimeException("SM4创建秘钥失败", e);
    }
  }

  // ==================================================================================
  // ==================================================================================
  // ==================================================================================

  /**
   * 字节数组加密成字符串
   *
   * @param source 源字节数组
   * @return 字符串
   */
  public static String encodeToString(byte[] source) {
    return Base64.getEncoder().encodeToString(source);
  }

  /**
   * 字节数组加密成字符串
   *
   * @param target 被转换后的字符串
   * @return 字符串
   */
  public static byte[] decodeToByte(String target) {
    return Base64.getDecoder().decode(target);
  }
}
